package com.gitee.simons.gateway.config;

import com.gitee.simons.common.bean.JsonResult;
import com.gitee.simons.common.bean.TokenInfo;
import com.gitee.simons.common.config.GlobalConfig;
import com.gitee.simons.common.utils.GsonUtil;
import com.gitee.simons.common.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.RequestMethod;
import reactor.core.publisher.Mono;

/**
 * token拦截器
 *
 * @author keriezhang
 * @date 2016/10/31
 */
@Slf4j
public class JwtCheckGatewayFilterFactory  extends AbstractGatewayFilterFactory<JwtCheckGatewayFilterFactory.Config> {

    @Value("${swagger.enable}")
    private boolean enable;

    private static final String[] SWAGGER_WHILE_LIST = new String[]{"/swagger-resources", "/api-docs", "/swagger-ui"};

    private static final String[] SYS_WHILE_LIST = new String[]{"/login"};

    public JwtCheckGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String method = exchange.getRequest().getMethod().name();
            // 如果是option方法跳过校验
            if(method.equals(RequestMethod.OPTIONS.name())) {
                // 将用户id作为参数传递下去
                return chain.filter(exchange);
            }

            String urlInfo = exchange.getRequest().getURI().toString();
            log.info("url：{}", urlInfo) ;
            // 判断是否开启swagger
            if (enable) {
                // 判断是否在白名单中
                for (String str : SWAGGER_WHILE_LIST) {
                    // 存在于白名单中就直接跳过
                    if (urlInfo.contains(str)) {
                        // 对该请求进行路由
                        return chain.filter(exchange);
                    }
                }
            }
            // 判断是否在系统白名单中
            for (String str : SYS_WHILE_LIST) {
                if (urlInfo.contains(str)) {
                    // 对该请求进行路由
                    return chain.filter(exchange);
                }
            }

            String jwtToken = exchange.getRequest().getHeaders().getFirst("token");
            // 校验jwtToken的合法性
            if (jwtToken != null) {
                // 合法
                if(this.handle(jwtToken)) {
                    // 传递下去
                    return chain.filter(exchange);
                }
            }

            //不合法(响应未登录的异常)
            ServerHttpResponse response = exchange.getResponse();
            //设置headers
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
            httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
            //设置body
            String warningStr = GsonUtil.gson.toJson(JsonResult.fail("token校验失败"));
            DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());

            return response.writeWith(Mono.just(bodyDataBuffer));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

    /**
     * 校验逻辑
     * @param tokenStr
     * @return
     */
    private boolean handle(String tokenStr) {
        String token = StringUtils.trim(tokenStr);
        //未登录的情况提示
        if (StringUtils.isBlank(token)) {
            log.info("token为空");
            return false;
        }
        TokenInfo tokenInfo = JwtUtil.verifyToken(token, TokenInfo.class, GlobalConfig.TOKEN_SECRET);
        if (tokenInfo == null) {
            log.info("token校验失败，token有误");
            return false;
        }
        return true;
    }
}
